#include "erunner.h"

LaneChannelERunnerSoftmemReadSender::LaneChannelERunnerSoftmemReadSender(JObject *parent) :
    LanePortSender(parent),
    dst_uri(new PortOut<int>(this)),
    sb(new PortOut<bool>(this)),
    r_addr_0(new PortOut<int>(this)),
    r_addr_0_wait(new PortOut<bool>(this)),
    r_ain_0_wait(new PortOut<bool>(this)),
    r_addr_1(new PortOut<int>(this)),
    r_addr_1_wait(new PortOut<bool>(this)),
    r_ain_1_wait(new PortOut<bool>(this)),
    op_code(new PortOut<AluOpCode>(this)),
    dst_pid(new PortOut<int>(this))
{
}

void LaneChannelERunnerSoftmemReadSender::connect(LaneChannelERunnerSoftmemReadReceiver *sender)
{
    dst_uri->connect(sender->dst_uri);
    sb->connect(sender->sb);
    r_addr_0->connect(sender->r_addr_0);
    r_addr_0_wait->connect(sender->r_addr_0_wait);
    r_ain_0_wait->connect(sender->r_ain_0_wait);
    r_addr_1->connect(sender->r_addr_1);
    r_addr_1_wait->connect(sender->r_addr_1_wait);
    r_ain_1_wait->connect(sender->r_ain_1_wait);
    op_code->connect(sender->op_code);
    dst_pid->connect(sender->dst_pid);
}

void LaneChannelERunnerSoftmemReadSender::put(int data_dst_uri, bool data_sb, int data_r_addr_0, bool data_r_addr_0_wait, bool data_r_ain_0_wait, int data_r_addr_1, bool data_r_addr_1_wait, bool data_r_ain_1_wait, AluOpCode data_op_code, int data_dst_pid)
{
    dst_uri->put(data_dst_uri);
    sb->put(data_sb);
    r_addr_0->put(data_r_addr_0);
    r_addr_0_wait->put(data_r_addr_0_wait);
    r_ain_0_wait->put(data_r_ain_0_wait);
    r_addr_1->put(data_r_addr_1);
    r_addr_1_wait->put(data_r_addr_1_wait);
    r_ain_1_wait->put(data_r_ain_1_wait);
    op_code->put(data_op_code);
    dst_pid->put(data_dst_pid);
}

void LaneChannelERunnerSoftmemReadSender::put_bypass(LaneChannelERunnerSoftmemReadReceiver *receiver)
{
    dst_uri->put(receiver->dst_uri->get());
    sb->put(receiver->sb->get());
    r_addr_0->put(receiver->r_addr_0->get());
    r_addr_0_wait->put(receiver->r_addr_0_wait->get());
    r_ain_0_wait->put(receiver->r_ain_0_wait->get());
    r_addr_1->put(receiver->r_addr_1->get());
    r_addr_1_wait->put(receiver->r_addr_1_wait->get());
    r_ain_1_wait->put(receiver->r_ain_1_wait->get());
    op_code->put(receiver->op_code->get());
    dst_pid->put(receiver->dst_pid->get());
}

bool LaneChannelERunnerSoftmemReadSender::is_any_full()
{
    return dst_uri->is_full() || sb->is_full() || r_addr_0->is_full() || r_addr_0_wait->is_full() || r_ain_0_wait->is_full() || r_addr_1->is_full() || r_addr_1_wait->is_full() || r_ain_1_wait->is_full() || op_code->is_full() || dst_pid->is_full();
}

LaneChannelERunnerSoftmemReadReceiver::LaneChannelERunnerSoftmemReadReceiver(JObject *parent) :
    LanePortReceiver(parent),
    dst_uri(new PortIn<int>(this, -1)),
    sb(new PortIn<bool>(this, -1)),
    r_addr_0(new PortIn<int>(this, -1)),
    r_addr_0_wait(new PortIn<bool>(this, -1)),
    r_ain_0_wait(new PortIn<bool>(this, -1)),
    r_addr_1(new PortIn<int>(this, -1)),
    r_addr_1_wait(new PortIn<bool>(this, -1)),
    r_ain_1_wait(new PortIn<bool>(this, -1)),
    op_code(new PortIn<AluOpCode>(this, -1)),
    dst_pid(new PortIn<int>(this, -1))
{
}

LaneChannelERunnerSoftmemReadPack LaneChannelERunnerSoftmemReadReceiver::get()
{
    LaneChannelERunnerSoftmemReadPack tmp_885190552;
    tmp_885190552.dst_uri = dst_uri->get();
    tmp_885190552.sb = sb->get();
    tmp_885190552.r_addr_0 = r_addr_0->get();
    tmp_885190552.r_addr_0_wait = r_addr_0_wait->get();
    tmp_885190552.r_ain_0_wait = r_ain_0_wait->get();
    tmp_885190552.r_addr_1 = r_addr_1->get();
    tmp_885190552.r_addr_1_wait = r_addr_1_wait->get();
    tmp_885190552.r_ain_1_wait = r_ain_1_wait->get();
    tmp_885190552.op_code = op_code->get();
    tmp_885190552.dst_pid = dst_pid->get();
    return tmp_885190552;
}

bool LaneChannelERunnerSoftmemReadReceiver::is_any_empty()
{
    return dst_uri->is_empty() || sb->is_empty() || r_addr_0->is_empty() || r_addr_0_wait->is_empty() || r_ain_0_wait->is_empty() || r_addr_1->is_empty() || r_addr_1_wait->is_empty() || r_ain_1_wait->is_empty() || op_code->is_empty() || dst_pid->is_empty();
}

bool LaneChannelERunnerSoftmemReadReceiver::is_any_full()
{
    return dst_uri->is_full() || sb->is_full() || r_addr_0->is_full() || r_addr_0_wait->is_full() || r_ain_0_wait->is_full() || r_addr_1->is_full() || r_addr_1_wait->is_full() || r_ain_1_wait->is_full() || op_code->is_full() || dst_pid->is_full();
}

ChannelERunnerSoftmemSender::ChannelERunnerSoftmemSender(JObject *parent) :
    ChannelPortSender(parent),
     Read(new LaneChannelERunnerSoftmemReadSender(this))
{
}

ChannelERunnerSoftmemReceiver::ChannelERunnerSoftmemReceiver(JObject *parent) :
    ChannelPortReceiver(parent),
    Read(new LaneChannelERunnerSoftmemReadReceiver(this))
{
}

void ChannelERunnerSoftmem::connect(ChannelERunnerSoftmemSender *sender, ChannelERunnerSoftmemReceiver *receiver)
{
    sender->Read->connect(receiver->Read);
}

NodeERunner::NodeERunner(Node *parent, NodeERunnerParam params) :
    Node(parent)
{
    const_num_of_alu = params.num_of_alu;
    const_peer_id = params.peer_id;
    const_total_peers = params.total_peers;
    const_base_ptrs = params.base_ptrs;
    reg_is_running = false;
    reg_completed_alu = 0;
    reg_nano_op_count = 0;
    reg_alu_arbiter = 0;
    List<bool> tmp_885266640;
    for(int temp_885061784=0; temp_885061784<const_num_of_alu; temp_885061784+=1)
    {
        tmp_885266640.append(false);
    }
    reg_alu_enable = tmp_885266640;
    List<int> tmp_885267088;
    for(int temp_885062288=0; temp_885062288<const_num_of_alu; temp_885062288+=1)
    {
        tmp_885267088.append(0);
    }
    reg_alu_dst = tmp_885267088;
    List<int> tmp_885267536;
    for(int temp_885061672=0; temp_885061672<const_num_of_alu; temp_885061672+=1)
    {
        tmp_885267536.append(0);
    }
    reg_alu_src_addr0 = tmp_885267536;
    List<int> tmp_885267984;
    for(int temp_885061112=0; temp_885061112<const_num_of_alu; temp_885061112+=1)
    {
        tmp_885267984.append(0);
    }
    reg_alu_src_addr1 = tmp_885267984;
    List<int> tmp_885268432;
    for(int temp_885063520=0; temp_885063520<const_num_of_alu; temp_885063520+=1)
    {
        tmp_885268432.append(0);
    }
    reg_alu_len_count = tmp_885268432;
    port_nano_op_receiver = new ChannelExecOpFabricReceiver(this);
    List<ChannelERunnerSoftmemSender *> tmp_885335096;
    for(int temp_884998944=0; temp_884998944<const_num_of_alu; temp_884998944+=1)
    {
        tmp_885335096.append(new ChannelERunnerSoftmemSender(this));
    }
    port_softmem_senders = tmp_885335096;
}

NodeTaskList NodeERunner::tasks() const
{
    NodeTaskList list;
    list.append(static_cast<NodeTask>(&NodeERunner::task_dispatch_execution));
    list.append(static_cast<NodeTask>(&NodeERunner::task_fetch_op));
    return list;
}

void NodeERunner::task_fetch_op()
{
    if(reg_is_running)
    {
        return;
    }
    if(!(port_nano_op_receiver->Bus->is_any_empty()))
    {
        LaneChannelExecOpFabricBusPack ret_885000176 = port_nano_op_receiver->Bus->get();
        reg_nano_op = ret_885000176.nano_op;
        reg_completed_alu = 0;
        reg_nano_op_count = 0;
        if((reg_nano_op.alu)==(0))
        {
            reg_nano_op.alu = (1)<<(reg_alu_arbiter);
            reg_alu_arbiter += 1;
            if(((reg_alu_arbiter)==(const_num_of_alu))||((reg_alu_arbiter)>(const_num_of_alu)))
            {
                reg_alu_arbiter = 0;
            }
        }
        reg_peer_count = 0;
        for(int bin_id=0; bin_id<const_peer_id; bin_id+=1)
        {
            if(((reg_nano_op.peer_id)&((1)<<(bin_id)))>(0))
            {
                reg_peer_count += 1;
            }
        }
        reg_alu_count = 0;
        for(int bin_id=0; bin_id<const_num_of_alu; bin_id+=1)
        {
            if(((reg_nano_op.alu)&((1)<<(bin_id)))>(0))
            {
                reg_alu_count += 1;
            }
        }
        for(int ii=0; ii<const_num_of_alu; ii+=1)
        {
            reg_alu_mask = (1)<<(ii);
            if(((static_cast<int>(reg_nano_op.alu))&(reg_alu_mask))>(0))
            {
                reg_alu_offset = 0;
                for(int bin_id=0; bin_id<const_num_of_alu; bin_id+=1)
                {
                    if(((reg_nano_op.alu)&((1)<<(bin_id)))&&((bin_id)<(ii)))
                    {
                        reg_alu_offset += 1;
                    }
                }
                reg_total_alu_offset = ((reg_peer_count)*(reg_alu_count))+(reg_alu_offset);
                reg_alu_dst[ii] = (reg_nano_op.dst_addr)+((reg_total_alu_offset)*(reg_nano_op.dst_increase));
                reg_alu_src_addr0[ii] = reg_nano_op.src_addr_0;
                reg_alu_src_addr1[ii] = reg_nano_op.src_addr_1;
                reg_alu_len_count[ii] = 0;
                reg_alu_enable[ii] = true;
                reg_nano_op_count += 1;
            }
            else
            {
                reg_alu_enable[ii] = false;
            }
        }
        if((reg_nano_op_count)>(0))
        {
            reg_is_running = true;
        }
    }
}

void NodeERunner::task_dispatch_execution()
{
    if(!(reg_is_running))
    {
        return;
    }
    for(int ii=0; ii<const_num_of_alu; ii+=1)
    {
        if((!(reg_alu_enable[ii]))||(port_softmem_senders[ii]->Read->is_any_full()))
        {
            continue;
        }
        port_softmem_senders[ii]->Read->put((reg_nano_op.dst_enable_offset) ? ((reg_alu_dst[ii])+(const_base_ptrs[ii])) : (reg_alu_dst[ii]), reg_nano_op.dst_sb, (reg_nano_op.src_enable_offset_0) ? ((reg_alu_src_addr0[ii])+(const_base_ptrs[ii])) : (reg_alu_src_addr0[ii]), reg_nano_op.src_wait_passin_0, reg_nano_op.src_wait_aluin_0, (reg_nano_op.src_enable_offset_1) ? ((reg_alu_src_addr1[ii])+(const_base_ptrs[ii])) : (reg_alu_src_addr1[ii]), reg_nano_op.src_wait_passin_1, reg_nano_op.src_wait_aluin_1, reg_nano_op.op_code, reg_nano_op.dst_peer_id);
        reg_alu_len_count[ii] += 1;
        if((reg_alu_len_count[ii])<(reg_nano_op.len_limit))
        {
            reg_alu_dst[ii] += reg_nano_op.dst_stride;
            reg_alu_src_addr0[ii] += reg_nano_op.src_stride_0;
            if(((reg_alu_src_addr0[ii])==(reg_nano_op.src_limit_0))||((reg_alu_src_addr0[ii])>(reg_nano_op.src_limit_0)))
            {
                reg_alu_src_addr0[ii] = reg_nano_op.src_addr_0;
            }
            reg_alu_src_addr1[ii] += reg_nano_op.src_stride_1;
            if(((reg_alu_src_addr1[ii])==(reg_nano_op.src_limit_1))||((reg_alu_src_addr1[ii])>(reg_nano_op.src_limit_1)))
            {
                reg_alu_src_addr1[ii] = reg_nano_op.src_addr_1;
            }
        }
        else
        {
            reg_completed_alu += 1;
            reg_alu_enable[ii] = false;
        }
    }
    if((reg_completed_alu)==(reg_nano_op_count))
    {
        reg_is_running = false;
    }
}